package com.weblog.article.service;

import com.weblog.article.client.UserClient;
import com.weblog.article.dao.ArticleDao;
import com.weblog.article.dao.CommentDao;
import com.weblog.model.article.Comment;
import com.weblog.model.utils.CategoryTreeUtil;
import entity.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import util.IdWorker;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * comment服务层
 *
 * @author Administrator
 */
@Service
public class CommentService {

    @Autowired
    private CommentDao commentDao;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private UserClient userClient;

    @Autowired
    private ArticleDao articleDao;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 多条件分页查询
     * TODO 改成VO
     * @param page
     * @param size
     * @param searchMap
     * @return
     */
    public Page<Comment> qureyByPage(int page, int size, Map<String, Object> searchMap) {
        Query query = new Query();
        PageRequest pageRequest = PageRequest.of(page - 1, size);

        if (!"".equals(searchMap.get("content")) && searchMap.get("content") != null) {
            //内容模糊查询
            //Pattern pattern=Pattern.compile("^.*"+(String) searchMap.get("content")+".*$",Pattern.CASE_INSENSITIVE);
            //query.addCriteria(Criteria.where("content").regex(pattern));
            return commentDao.findByStateEqualsAndContentLikeOrderByCreatetimeDesc((String) searchMap.get("state"), (String) searchMap.get("content"), pageRequest);
        }
        if ("1".equals(searchMap.get("ishot"))) {
            //查询热门评论

            return commentDao.findTop20ByStateOrderByThumbupDesc((String) searchMap.get("state"), pageRequest);
        }
        //根据状态查询
        return commentDao.findByStateOrderByCreatetimeDesc((String) searchMap.get("state"), pageRequest);


    }

    /**
     * 根据id查询评论信息
     *
     * @param id
     * @return
     */
    public Comment findById(String id) {
        try {
            return commentDao.findById(id).get();
        } catch (Exception e) {
            return null;
        }

    }

    /**
     * 根据父级id查询父级评论
     *
     * @param parentid
     * @return
     */
    public Comment queryParentCommentByParentId(String parentid) {

        try {
            return commentDao.findById(parentid).get();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 回复评论
     *
     * @param comment
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public int reply(Comment comment) {
        final int LOGIN_USER_ABNORMAL = 0;
        final int OK = 1;
        final int ACCESS_ERROR = 2;
        final int PARENT_COMMENT_NOT_FOUND = 3;


        comment.set_id(idWorker.nextId() + "");
        comment.setReplynum(0);
        comment.setState("1");
        comment.setThumbup(0L);
        comment.setCreatetime(new Date());
        comment.setUserid((String) request.getAttribute("id_A"));
        Result resultUser = userClient.findUserNameById((String) request.getAttribute("id_A"));
        if (!resultUser.isFlag()) {
            return LOGIN_USER_ABNORMAL;//当前登录用户状态异常
        } else {
            comment.setUsername((String) resultUser.getData());
        }

        String token = (String) request.getAttribute("claims_admin_A");
        if (StringUtils.isNotBlank(token)) {
            //普通管理员
            Result access = userClient.isAccess("role_comment", "comment_reply");
            if ((int) access.getData() == 2) {
                return ACCESS_ERROR;//权限不足
            }
            try {
                //父评论存在
                commentDao.findById(comment.getParentid()).get();
            } catch (Exception e) {
                //父评论不存在
                return PARENT_COMMENT_NOT_FOUND;
            }
            commentDao.save(comment);
            //增加父评论的回复数
            incrReplyNam(comment.getParentid());
            //增加文章回复数
            articleDao.incrArticleCommentNum(comment.getArticleid());
            sendMsg("comment",comment.getArticleid());
            return OK;
        }
        //超级管理员
        commentDao.save(comment);
        //增加父评论的回复数
        incrReplyNam(comment.getParentid());
        //增加文章回复数
        articleDao.incrArticleCommentNum(comment.getArticleid());
        sendMsg("comment",comment.getArticleid());

        return OK;
    }

    /**
     * 发送消息
     * @param aid
     */
    private void sendMsg(String type,String aid) {

        try {
            rabbitTemplate.convertAndSend("article."+type,aid);
        }catch (AmqpException e){
            e.printStackTrace();
        }
    }
    /**
     * 增加父评论回复数
     *
     * @param id 上一级评论id
     */
    private void incrReplyNam(String id) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        Update update = new Update();
        update.inc("replynum", 1);
        mongoTemplate.updateFirst(query, update, "comment");
    }




    /**
     * 点赞
     *
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public int thumbup(String id) {
        try {
            Query query = new Query();
            query.addCriteria(Criteria.where("_id").is(id));
            Update update = new Update();
            update.inc("thumbup", 1);
            mongoTemplate.updateFirst(query, update, "comment");
            return 1;
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 禁用评论
     *
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public int disableComment(String id) {
        String token = (String) request.getAttribute("claims_admin_A");
        if (StringUtils.isNotBlank(token)) {
            //普通管理员
            Result result = userClient.isAccess("role_comment", "comment_delete");
            if ((int) result.getData() == 2) {
                return 2;
            }
            disable(id);
            return 1;
        }
        //超级管理员
        disable(id);
        return 1;
    }

    /**
     * 禁用评论操作
     *
     * @param id
     */
    private void disable(String id) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        Update update = new Update();
        update.set("state", "0");
        mongoTemplate.updateFirst(query, update, "comment");
    }

    /**
     * 发表评论
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public int publishComment( Comment comment) {
        final int LOGIN_USER_ABNORMAL = 0;
        final int OK = 1;
        final int ACCESS_ERROR = 2;

        comment.set_id(idWorker.nextId() + "");
        comment.setParentid("0");
        comment.setReplynum(0);
        comment.setState("1");
        comment.setThumbup(0L);
        comment.setCreatetime(new Date());
        comment.setUserid((String) request.getAttribute("id_A"));
        Result resultUser = userClient.findUserNameById((String) request.getAttribute("id_A"));
        if (!resultUser.isFlag()) {
            //当前登录用户状态异常
            return LOGIN_USER_ABNORMAL;
        } else {
            comment.setUsername((String) resultUser.getData());
        }

        String token = (String) request.getAttribute("claims_admin_A");
        if (StringUtils.isNotBlank(token)) {
            //普通管理员
            Result access = userClient.isAccess("role_comment", "comment_publish");
            if ((int) access.getData() == 2) {
                return ACCESS_ERROR;//权限不足
            }

            commentDao.save(comment);
            //增加文章的回复数
            articleDao.incrArticleCommentNum(comment.getArticleid());
            return OK;
        }
        //超级管理员
        commentDao.save(comment);
        //增加文章的回复数
        articleDao.incrArticleCommentNum(comment.getArticleid());
        return OK;
    }

    /**
     * 删除评论，连同其回复一并删除
     * 减少所有父评论的回复数
     * 1.若评论为顶级评论，则只减少文章的评论数
     * 2.若评论为二级评论，则减少该评论的顶级评论的回复数并减少文章的回复数
     * 3.若评论为三级及以上，则先减少评论的顶级评论，再异步减少顶级和该评论中间的评论的回复数
     * 4.完成后发送消息同步ES的数据
     * @param map
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteComment(Map<String,String>map){
        Query query=new Query();
        /**
         * 条件：
         * 1.state为1
         * 2.parentid为0，即去掉最顶级评论
         * 3.只查询id和parentid，其他的多余
         */
        query.addCriteria(Criteria.where("state").is("1").norOperator(Criteria.where("parentid").is("0")))
                .fields().include("_id").include("parentid");

        List<Comment> comments = mongoTemplate.find(query, Comment.class);
        List<String> delIds = CategoryTreeUtil.getDelComment(map.get("id"), comments);
        delIds.add(map.get("id"));
        query=new Query();
        query.addCriteria(Criteria.where("_id").in(delIds));
        List<Comment> delComment = mongoTemplate.find(query, Comment.class);

        commentDao.deleteAll(delComment);

        //减少对应文章的评论数
        articleDao.decrArticleCommentNum(map.get("articleid"),delIds.size());

    }





    /**
     * 根据文章id查询所有父级分类(前端默认展示父级评论,子评论在查看父级评论的回复时再查询)
     * @param aid
     */
    public List<Comment> findByAid(String aid,int page,int size){
       Query query=new Query();
        Pageable pageable=PageRequest.of(page-1,size);
        query.addCriteria(Criteria.where("aid").is(aid).andOperator(Criteria.where("parentid").is("0")))
               .with(pageable)
                .with(Sort.by("thubmup").descending())
                .with(Sort.by("createtime").ascending());
        return mongoTemplate.find(query, Comment.class);

    }

    /**
     * 根据id查询下一级所有评论(前台，去掉state为0的评论)
     *
     * @param id
     * @return
     */
    public List<Comment> findNextLevelComments(String id) {
        return commentDao.findCommentsByParentidAndStateOrderByCreatetimeDesc(id,"1");
    }
    /**
     * 根据id查询下一级所有评论(后台，会查询state为0的评论)
     *
     * @param id
     * @return
     */
    public List<Comment> queryNextLevelComments(String id) {
        return commentDao.findCommentsByParentid(id);
    }
    /**
     * 根据文章id集合查询评论数量
     * @param aids
     * @return
     */
    public Long countCommentByAids(List<String> aids) {
        Query query = new Query();
        Long commentNum = 0L;
        /*
            不可以在遍历aids循环中添加条件，会因重复添加articleid字段的Criteria报错，这里使用in
            org.springframework.data.mongodb.InvalidMongoDbApiUsageException:
            Due to limitations of the com.mongodb.BasicDocument, you can't add a second 'createdDate'
            expression specified as 'createdDate:
         */
        query.addCriteria(Criteria.where("articleid").in(aids));
        commentNum = mongoTemplate.count(query, "comment");

        return commentNum;
    }

    /**
     * 查询总记录数
     * @return
     */
    public long count() {
        return commentDao.count();
    }
}
